package com.zhuhjay.service.system.aspectj;

import com.zhuhjay.common.base.enums.HttpCode;
import com.zhuhjay.common.base.exception.ApiLimiterException;
import com.zhuhjay.common.base.exception.BasicBusinessException;
import com.zhuhjay.common.base.model.vo.HttpResult;
import com.zhuhjay.common.web.annotation.RecordLog;
import com.zhuhjay.service.system.util.LogUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.stream.Stream;

/**
 * 记录日志切面
 * @author ZhuHJay
 * @date 2023/1/30 20:35
 */
@Order(2)
@Aspect
@Component
public class RecordLogAspect {

    @Around("@annotation(recordLog)")
    public Object around(ProceedingJoinPoint pjp, RecordLog recordLog) throws Throwable {
        // 计时器
        StopWatch stopWatch = new StopWatch();
        Object result = null;
        Throwable t = null;
        stopWatch.start();
        try {
            // 执行真实的控制器方法
            result = pjp.proceed();
        } catch (Throwable throwable) {
            t = throwable;
        }
        stopWatch.stop();
        // 保存日志
        recordLog(pjp, recordLog, result, t, stopWatch);
        // 如果异常不为空，那么就向外抛出
        if (t != null) {
            throw t;
        }
        return result;
    }

    private void recordLog(
            ProceedingJoinPoint pjp, RecordLog recordLog, Object result,
            Throwable t, StopWatch stopWatch) {
        Signature signature = pjp.getSignature();

        String methodName = pjp.getTarget().getClass().getSimpleName() + "." + signature.getName();
        String desc = recordLog.value();
        Object[] args = pjp.getArgs();
        HttpCode code = HttpCode.SUCCESS;
        Object res = null;
        int processTime = (int) stopWatch.getTotalTimeMillis();

        if (t != null) {
            // 判断异常的类型，来设置响应码
            if (t instanceof BasicBusinessException || t instanceof ApiLimiterException) {
                code = HttpCode.USER_ERROR;
            } else {
                code = HttpCode.SERVER_ERROR;
            }
            // 可能没有信息，判断一下防止空指针
            String message = t.getMessage();
            if (message == null) {
                message = t.toString();
            }
            res = message;
        } else {
            // 如果返回值为 HttpResult 才需要获取对应的响应状态码
            if (result instanceof HttpResult) {
                code = Stream.of(HttpCode.values())
                        .filter(httpCode -> httpCode.getCode() == ((HttpResult<?>) result).getCode())
                        .findFirst().orElse(HttpCode.SUCCESS);
            }
            res = result;
        }
        LogUtil.record(methodName, desc, args, res, code, processTime);
    }

}
